<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<meta name="generator" content="AsciiDoc 8.6.10" />
<title>Pacemaker Access Control Lists</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */

/* Default font. */
body {
  font-family: Georgia,serif;
}

/* Title font. */
h1, h2, h3, h4, h5, h6,
div.title, caption.title,
thead, p.table.header,
#toctitle,
#author, #revnumber, #revdate, #revremark,
#footer {
  font-family: Arial,Helvetica,sans-serif;
}

body {
  margin: 1em 5% 1em 5%;
}

a {
  color: blue;
  text-decoration: underline;
}
a:visited {
  color: fuchsia;
}

em {
  font-style: italic;
  color: navy;
}

strong {
  font-weight: bold;
  color: #083194;
}

h1, h2, h3, h4, h5, h6 {
  color: #527bbd;
  margin-top: 1.2em;
  margin-bottom: 0.5em;
  line-height: 1.3;
}

h1, h2, h3 {
  border-bottom: 2px solid silver;
}
h2 {
  padding-top: 0.5em;
}
h3 {
  float: left;
}
h3 + * {
  clear: left;
}
h5 {
  font-size: 1.0em;
}

div.sectionbody {
  margin-left: 0;
}

hr {
  border: 1px solid silver;
}

p {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

ul, ol, li > p {
  margin-top: 0;
}
ul > li     { color: #aaa; }
ul > li > * { color: black; }

.monospaced, code, pre {
  font-family: "Courier New", Courier, monospace;
  font-size: inherit;
  color: navy;
  padding: 0;
  margin: 0;
}
pre {
  white-space: pre-wrap;
}

#author {
  color: #527bbd;
  font-weight: bold;
  font-size: 1.1em;
}
#email {
}
#revnumber, #revdate, #revremark {
}

#footer {
  font-size: small;
  border-top: 2px solid silver;
  padding-top: 0.5em;
  margin-top: 4.0em;
}
#footer-text {
  float: left;
  padding-bottom: 0.5em;
}
#footer-badges {
  float: right;
  padding-bottom: 0.5em;
}

#preamble {
  margin-top: 1.5em;
  margin-bottom: 1.5em;
}
div.imageblock, div.exampleblock, div.verseblock,
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
div.admonitionblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
div.admonitionblock {
  margin-top: 2.0em;
  margin-bottom: 2.0em;
  margin-right: 10%;
  color: #606060;
}

div.content { /* Block element content. */
  padding: 0;
}

/* Block element titles. */
div.title, caption.title {
  color: #527bbd;
  font-weight: bold;
  text-align: left;
  margin-top: 1.0em;
  margin-bottom: 0.5em;
}
div.title + * {
  margin-top: 0;
}

td div.title:first-child {
  margin-top: 0.0em;
}
div.content div.title:first-child {
  margin-top: 0.0em;
}
div.content + div.title {
  margin-top: 0.0em;
}

div.sidebarblock > div.content {
  background: #ffffee;
  border: 1px solid #dddddd;
  border-left: 4px solid #f0f0f0;
  padding: 0.5em;
}

div.listingblock > div.content {
  border: 1px solid #dddddd;
  border-left: 5px solid #f0f0f0;
  background: #f8f8f8;
  padding: 0.5em;
}

div.quoteblock, div.verseblock {
  padding-left: 1.0em;
  margin-left: 1.0em;
  margin-right: 10%;
  border-left: 5px solid #f0f0f0;
  color: #888;
}

div.quoteblock > div.attribution {
  padding-top: 0.5em;
  text-align: right;
}

div.verseblock > pre.content {
  font-family: inherit;
  font-size: inherit;
}
div.verseblock > div.attribution {
  padding-top: 0.75em;
  text-align: left;
}
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
div.verseblock + div.attribution {
  text-align: left;
}

div.admonitionblock .icon {
  vertical-align: top;
  font-size: 1.1em;
  font-weight: bold;
  text-decoration: underline;
  color: #527bbd;
  padding-right: 0.5em;
}
div.admonitionblock td.content {
  padding-left: 0.5em;
  border-left: 3px solid #dddddd;
}

div.exampleblock > div.content {
  border-left: 3px solid #dddddd;
  padding-left: 0.5em;
}

div.imageblock div.content { padding-left: 0; }
span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }

dl {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
dt {
  margin-top: 0.5em;
  margin-bottom: 0;
  font-style: normal;
  color: navy;
}
dd > *:first-child {
  margin-top: 0.1em;
}

ul, ol {
    list-style-position: outside;
}
ol.arabic {
  list-style-type: decimal;
}
ol.loweralpha {
  list-style-type: lower-alpha;
}
ol.upperalpha {
  list-style-type: upper-alpha;
}
ol.lowerroman {
  list-style-type: lower-roman;
}
ol.upperroman {
  list-style-type: upper-roman;
}

div.compact ul, div.compact ol,
div.compact p, div.compact p,
div.compact div, div.compact div {
  margin-top: 0.1em;
  margin-bottom: 0.1em;
}

tfoot {
  font-weight: bold;
}
td > div.verse {
  white-space: pre;
}

div.hdlist {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
div.hdlist tr {
  padding-bottom: 15px;
}
dt.hdlist1.strong, td.hdlist1.strong {
  font-weight: bold;
}
td.hdlist1 {
  vertical-align: top;
  font-style: normal;
  padding-right: 0.8em;
  color: navy;
}
td.hdlist2 {
  vertical-align: top;
}
div.hdlist.compact tr {
  margin: 0;
  padding-bottom: 0;
}

.comment {
  background: yellow;
}

.footnote, .footnoteref {
  font-size: 0.8em;
}

span.footnote, span.footnoteref {
  vertical-align: super;
}

#footnotes {
  margin: 20px 0 20px 0;
  padding: 7px 0 0 0;
}

#footnotes div.footnote {
  margin: 0 0 5px 0;
}

#footnotes hr {
  border: none;
  border-top: 1px solid silver;
  height: 1px;
  text-align: left;
  margin-left: 0;
  width: 20%;
  min-width: 100px;
}

div.colist td {
  padding-right: 0.5em;
  padding-bottom: 0.3em;
  vertical-align: top;
}
div.colist td img {
  margin-top: 0.3em;
}

@media print {
  #footer-badges { display: none; }
}

#toc {
  margin-bottom: 2.5em;
}

#toctitle {
  color: #527bbd;
  font-size: 1.1em;
  font-weight: bold;
  margin-top: 1.0em;
  margin-bottom: 0.1em;
}

div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
  margin-top: 0;
  margin-bottom: 0;
}
div.toclevel2 {
  margin-left: 2em;
  font-size: 0.9em;
}
div.toclevel3 {
  margin-left: 4em;
  font-size: 0.9em;
}
div.toclevel4 {
  margin-left: 6em;
  font-size: 0.9em;
}

span.aqua { color: aqua; }
span.black { color: black; }
span.blue { color: blue; }
span.fuchsia { color: fuchsia; }
span.gray { color: gray; }
span.green { color: green; }
span.lime { color: lime; }
span.maroon { color: maroon; }
span.navy { color: navy; }
span.olive { color: olive; }
span.purple { color: purple; }
span.red { color: red; }
span.silver { color: silver; }
span.teal { color: teal; }
span.white { color: white; }
span.yellow { color: yellow; }

span.aqua-background { background: aqua; }
span.black-background { background: black; }
span.blue-background { background: blue; }
span.fuchsia-background { background: fuchsia; }
span.gray-background { background: gray; }
span.green-background { background: green; }
span.lime-background { background: lime; }
span.maroon-background { background: maroon; }
span.navy-background { background: navy; }
span.olive-background { background: olive; }
span.purple-background { background: purple; }
span.red-background { background: red; }
span.silver-background { background: silver; }
span.teal-background { background: teal; }
span.white-background { background: white; }
span.yellow-background { background: yellow; }

span.big { font-size: 2em; }
span.small { font-size: 0.6em; }

span.underline { text-decoration: underline; }
span.overline { text-decoration: overline; }
span.line-through { text-decoration: line-through; }

div.unbreakable { page-break-inside: avoid; }


/*
 * xhtml11 specific
 *
 * */

div.tableblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
div.tableblock > table {
  border: 3px solid #527bbd;
}
thead, p.table.header {
  font-weight: bold;
  color: #527bbd;
}
p.table {
  margin-top: 0;
}
/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
  border-style: none;
}
div.tableblock > table[frame="hsides"] {
  border-left-style: none;
  border-right-style: none;
}
div.tableblock > table[frame="vsides"] {
  border-top-style: none;
  border-bottom-style: none;
}


/*
 * html5 specific
 *
 * */

table.tableblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
thead, p.tableblock.header {
  font-weight: bold;
  color: #527bbd;
}
p.tableblock {
  margin-top: 0;
}
table.tableblock {
  border-width: 3px;
  border-spacing: 0px;
  border-style: solid;
  border-color: #527bbd;
  border-collapse: collapse;
}
th.tableblock, td.tableblock {
  border-width: 1px;
  padding: 4px;
  border-style: solid;
  border-color: #527bbd;
}

table.tableblock.frame-topbot {
  border-left-style: hidden;
  border-right-style: hidden;
}
table.tableblock.frame-sides {
  border-top-style: hidden;
  border-bottom-style: hidden;
}
table.tableblock.frame-none {
  border-style: hidden;
}

th.tableblock.halign-left, td.tableblock.halign-left {
  text-align: left;
}
th.tableblock.halign-center, td.tableblock.halign-center {
  text-align: center;
}
th.tableblock.halign-right, td.tableblock.halign-right {
  text-align: right;
}

th.tableblock.valign-top, td.tableblock.valign-top {
  vertical-align: top;
}
th.tableblock.valign-middle, td.tableblock.valign-middle {
  vertical-align: middle;
}
th.tableblock.valign-bottom, td.tableblock.valign-bottom {
  vertical-align: bottom;
}


/*
 * manpage specific
 *
 * */

body.manpage h1 {
  padding-top: 0.5em;
  padding-bottom: 0.5em;
  border-top: 2px solid silver;
  border-bottom: 2px solid silver;
}
body.manpage h2 {
  border-style: none;
}
body.manpage div.sectionbody {
  margin-left: 3em;
}

@media print {
  body.manpage div#toc { display: none; }
}


</style>
<script type="text/javascript">
/*<![CDATA[*/
var asciidoc = {  // Namespace.

/////////////////////////////////////////////////////////////////////
// Table Of Contents generator
/////////////////////////////////////////////////////////////////////

/* Author: Mihai Bazon, September 2002
 * http://students.infoiasi.ro/~mishoo
 *
 * Table Of Content generator
 * Version: 0.4
 *
 * Feel free to use this script under the terms of the GNU General Public
 * License, as long as you do not remove or alter this notice.
 */

 /* modified by Troy D. Hanson, September 2006. License: GPL */
 /* modified by Stuart Rackham, 2006, 2009. License: GPL */

// toclevels = 1..4.
toc: function (toclevels) {

  function getText(el) {
    var text = "";
    for (var i = el.firstChild; i != null; i = i.nextSibling) {
      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
        text += i.data;
      else if (i.firstChild != null)
        text += getText(i);
    }
    return text;
  }

  function TocEntry(el, text, toclevel) {
    this.element = el;
    this.text = text;
    this.toclevel = toclevel;
  }

  function tocEntries(el, toclevels) {
    var result = new Array;
    var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
    // Function that scans the DOM tree for header elements (the DOM2
    // nodeIterator API would be a better technique but not supported by all
    // browsers).
    var iterate = function (el) {
      for (var i = el.firstChild; i != null; i = i.nextSibling) {
        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
          var mo = re.exec(i.tagName);
          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
          }
          iterate(i);
        }
      }
    }
    iterate(el);
    return result;
  }

  var toc = document.getElementById("toc");
  if (!toc) {
    return;
  }

  // Delete existing TOC entries in case we're reloading the TOC.
  var tocEntriesToRemove = [];
  var i;
  for (i = 0; i < toc.childNodes.length; i++) {
    var entry = toc.childNodes[i];
    if (entry.nodeName.toLowerCase() == 'div'
     && entry.getAttribute("class")
     && entry.getAttribute("class").match(/^toclevel/))
      tocEntriesToRemove.push(entry);
  }
  for (i = 0; i < tocEntriesToRemove.length; i++) {
    toc.removeChild(tocEntriesToRemove[i]);
  }

  // Rebuild TOC entries.
  var entries = tocEntries(document.getElementById("content"), toclevels);
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    if (entry.element.id == "")
      entry.element.id = "_toc_" + i;
    var a = document.createElement("a");
    a.href = "#" + entry.element.id;
    a.appendChild(document.createTextNode(entry.text));
    var div = document.createElement("div");
    div.appendChild(a);
    div.className = "toclevel" + entry.toclevel;
    toc.appendChild(div);
  }
  if (entries.length == 0)
    toc.parentNode.removeChild(toc);
},


/////////////////////////////////////////////////////////////////////
// Footnotes generator
/////////////////////////////////////////////////////////////////////

/* Based on footnote generation code from:
 * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
 */

footnotes: function () {
  // Delete existing footnote entries in case we're reloading the footnodes.
  var i;
  var noteholder = document.getElementById("footnotes");
  if (!noteholder) {
    return;
  }
  var entriesToRemove = [];
  for (i = 0; i < noteholder.childNodes.length; i++) {
    var entry = noteholder.childNodes[i];
    if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
      entriesToRemove.push(entry);
  }
  for (i = 0; i < entriesToRemove.length; i++) {
    noteholder.removeChild(entriesToRemove[i]);
  }

  // Rebuild footnote entries.
  var cont = document.getElementById("content");
  var spans = cont.getElementsByTagName("span");
  var refs = {};
  var n = 0;
  for (i=0; i<spans.length; i++) {
    if (spans[i].className == "footnote") {
      n++;
      var note = spans[i].getAttribute("data-note");
      if (!note) {
        // Use [\s\S] in place of . so multi-line matches work.
        // Because JavaScript has no s (dotall) regex flag.
        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
        spans[i].innerHTML =
          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
        spans[i].setAttribute("data-note", note);
      }
      noteholder.innerHTML +=
        "<div class='footnote' id='_footnote_" + n + "'>" +
        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
        n + "</a>. " + note + "</div>";
      var id =spans[i].getAttribute("id");
      if (id != null) refs["#"+id] = n;
    }
  }
  if (n == 0)
    noteholder.parentNode.removeChild(noteholder);
  else {
    // Process footnoterefs.
    for (i=0; i<spans.length; i++) {
      if (spans[i].className == "footnoteref") {
        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
        href = href.match(/#.*/)[0];  // Because IE return full URL.
        n = refs[href];
        spans[i].innerHTML =
          "[<a href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
      }
    }
  }
},

install: function(toclevels) {
  var timerId;

  function reinstall() {
    asciidoc.footnotes();
    if (toclevels) {
      asciidoc.toc(toclevels);
    }
  }

  function reinstallAndRemoveTimer() {
    clearInterval(timerId);
    reinstall();
  }

  timerId = setInterval(reinstall, 500);
  if (document.addEventListener)
    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
  else
    window.onload = reinstallAndRemoveTimer;
}

}
asciidoc.install();
/*]]>*/
</script>
</head>
<body class="article">
<div id="header">
<h1>Pacemaker Access Control Lists</h1>
<span id="author">Tim Serong</span><br />
<span id="email"><code>&lt;<a href="mailto:tserong@novell.com">tserong@novell.com</a>&gt;</code></span><br />
</div>
<div id="content">
<div class="sect1">
<h2 id="_introduction">Introduction</h2>
<div class="sectionbody">
<div class="paragraph"><p>The various tools for administering Pacemaker clusters (crm_mon,
crm shell, cibadmin and friends, Python GUI, Hawk) can be used by
the <code>root</code> user, or any user in the <code>haclient</code> group.  By default,
these users have full read/write access.  Starting with Pacemaker
version 1.1.5, flexible access control lists are introduced to
provide different levels of administration to different users.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_prerequisites">Prerequisites</h2>
<div class="sectionbody">
<div class="ulist"><ul>
<li>
<p>
Users are regular UNIX users, so the same user accounts must
  be present on all nodes in the cluster.
</p>
</li>
<li>
<p>
All user accounts must be in the <code>haclient</code> group.
</p>
</li>
<li>
<p>
Pacemaker 1.1.5 or newer must be installed on all cluster nodes.
</p>
</li>
<li>
<p>
The CIB must be configured to use the pacemaker-1.1 or 1.2 schema.
  This can be set by running:
</p>
<div class="literalblock">
<div class="content">
<pre><code>cibadmin --modify --xml-text '&lt;cib validate-with="pacemaker-1.1"/&gt;'</code></pre>
</div></div>
</li>
<li>
<p>
The <code>enable-acl</code> option must be set.  If ACLs are not explicitly
  enabled, the previous behaviour will be used (i.e. all users in
  the <code>haclient</code> group have full access):
</p>
<div class="literalblock">
<div class="content">
<pre><code>crm configure property enable-acl=true</code></pre>
</div></div>
</li>
<li>
<p>
Once this is done, ACLs can be configured as described below.
</p>
</li>
<li>
<p>
Note that the <code>root</code> and <code>hacluster</code> users will always have full
  access.
</p>
</li>
<li>
<p>
If nonprivileged users will be using the crm shell and CLI tools
  (as opposed to only using Hawk or the Python GUI) they will need
  to have <code>/usr/sbin</code> added to their path.
</p>
</li>
</ul></div>
</div>
</div>
<div class="sect1">
<h2 id="_configuring_acls">Configuring ACLs</h2>
<div class="sectionbody">
<div class="paragraph"><p>Access control lists consist of an ordered set of access rules.
Each rule allows read or write access or denies access completely
to a part of the CIB.  Rules are typically combined to produce a
specific role, then users may be assigned to that role.  It is
also possible to configure ACLs directly for individual users.</p></div>
<div class="paragraph"><p>ACLs may be configured using the crm shell or the Python GUI.
The shell syntax is documented here.  Using the Python GUI should
be reasonably straightforward once the concepts are understood.</p></div>
<div class="paragraph"><p>Note that rules are applied from first to last with the first
matching rule being used.  This means specific <code>write</code> rules
usually need to be listed before general <code>read</code> rules.  Any
permission not explicitly granted is denied by default, but note
that <code>write</code> implies <code>read</code>, so there is no need to specify both
to allow full read/write access.</p></div>
<div class="sect2">
<h3 id="_minimum_required_acls">Minimum Required ACLs</h3>
<div class="paragraph"><p>In order for the various tools to work correctly, a certain minimum
amount of data must be readable by the user invoking the tool.  In
general, the safest thing to do is simply allow all users and roles
read access to the entire CIB.</p></div>
</div>
<div class="sect2">
<h3 id="_role_syntax">Role Syntax</h3>
<div class="paragraph"><p>An ACL role is a set of rules which describe access rights to
CIB.  Rules consist of an access right <code>read</code>, <code>write</code>, or <code>deny</code>
and a specification denoting part of the configuration to which
the access right applies.  The specification can be an XPath or a
combination of tag and id references.  If an attribute is appended,
then the specification applies only to that attribute of the matching
element.</p></div>
<div class="sect3">
<h4 id="_usage">Usage</h4>
<div class="literalblock">
<div class="content">
<pre><code>    role &lt;role-id&gt; rule [rule ...]

    rule :: acl-right cib-spec [attribute:&lt;attribute&gt;]

    acl-right :: read | write | deny

    cib-spec :: xpath-spec | tag-ref-spec
    xpath-spec :: xpath:&lt;xpath&gt;
    tag-ref-spec :: tag:&lt;tag&gt; | ref:&lt;id&gt; | tag:&lt;tag&gt; ref:&lt;id&gt;</code></pre>
</div></div>
</div>
<div class="sect3">
<h4 id="_example_role_read_only_access">Example Role: Read-only Access</h4>
<div class="literalblock">
<div class="content">
<pre><code>    role monitor \
        read xpath:"/cib"</code></pre>
</div></div>
<div class="paragraph"><p>This is a single rule which allows read-only access to the entire
CIB.  Users with this role will be able to view the status of
the cluster, but not make any changes.</p></div>
</div>
<div class="sect3">
<h4 id="_example_role_8220_operator_8221_access">Example Role: &#8220;Operator&#8221; Access</h4>
<div class="literalblock">
<div class="content">
<pre><code>    role operator \
        write xpath:"//crm_config//nvpair[@name='maintenance-mode']" \
        write xpath:"//op_defaults//nvpair[@name='record-pending']" \
        write xpath:"//nodes/node//nvpair[@name='standby']" \
        write xpath:"//resources//nvpair[@name='target-role']" \
        write xpath:"//resources//nvpair[@name='is-managed']" \
        write xpath:"//constraints/rsc_location" \
        read xpath:"/cib"</code></pre>
</div></div>
<div class="paragraph"><p>These rules specify that users with this role will be able to:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Turn maintenance mode on or off
</p>
</li>
<li>
<p>
Change whether pending operations are recorded
</p>
</li>
<li>
<p>
Put any node on standby, and bring any node back online
</p>
</li>
<li>
<p>
Start, stop, promote or demote any resource
</p>
</li>
<li>
<p>
Tell the cluster to manage, or not manage any resource
</p>
</li>
<li>
<p>
Migrate/move resources from node to note
</p>
</li>
<li>
<p>
View the status of the cluster
</p>
</li>
</ol></div>
<div class="paragraph"><p>Users with this role will not be able to reconfigure resources
(change parameters, operations, etc.) or colocation or ordering
constraints.</p></div>
</div>
<div class="sect3">
<h4 id="_example_role_full_access">Example Role: Full Access</h4>
<div class="literalblock">
<div class="content">
<pre><code>    role administrator \
        write xpath:"/cib"</code></pre>
</div></div>
<div class="paragraph"><p>This is a single rule which allows full read-write access to the
entire CIB.  Users with this role will have equivalent access to
the <code>root</code> and <code>hacluster</code> users.</p></div>
</div>
</div>
<div class="sect2">
<h3 id="_user_syntax">User Syntax</h3>
<div class="paragraph"><p>ACLs can be defined for individual users using the same syntax
as for roles.  Alternately, users can simply be assigned a given
role.  The latter is considered best practice.</p></div>
<div class="sect3">
<h4 id="_usage_2">Usage</h4>
<div class="literalblock">
<div class="content">
<pre><code>    user &lt;uid&gt; {role:&lt;role-ref&gt;|rule [rule ...]}

    rule :: acl-right cib-spec [attribute:&lt;attribute&gt;]

    acl-right :: read | write | deny

    cib-spec :: xpath-spec | tag-ref-spec
    xpath-spec :: xpath:&lt;xpath&gt;
    tag-ref-spec :: tag:&lt;tag&gt; | ref:&lt;id&gt; | tag:&lt;tag&gt; ref:&lt;id&gt;</code></pre>
</div></div>
</div>
<div class="sect3">
<h4 id="_example">Example</h4>
<div class="literalblock">
<div class="content">
<pre><code>    user alice role:monitor
    user bob role:operator</code></pre>
</div></div>
<div class="paragraph"><p>The above example assigns <code>alice</code> the <code>monitor</code> role and <code>bob</code> the
<code>operator</code> role.</p></div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_advanced_usage">Advanced Usage</h2>
<div class="sectionbody">
<div class="paragraph"><p>Because ACLs can refer to elements and attributes in the CIB in a
very granular way, it is possible to configure very specific rules.
A refinement of the &#8220;operator&#8221; role above would be to allow
manipulation of only a specific resource, for example:</p></div>
<div class="literalblock">
<div class="content">
<pre><code>    role bigdb_admin \
        write xpath:"//primitive[@id='bigdb']/meta_attributes/nvpair[@name='target-role']" \
        write xpath:"//primitive[@id='bigdb']/meta_attributes/nvpair[@name='is-managed']" \
        write xpath:"//constraints/rsc_location[@rsc='bigdb']" \
        read ref:"bigdb" \
        read xpath:"//nodes/node" uname \
        read xpath:"//nodes/node" type \
        read xpath:"//crm_config/cluster_property_set" \
        read xpath:"/cib/status"</code></pre>
</div></div>
<div class="paragraph"><p>The first four rules are specific for the <code>bigdb</code> resource. They
allow modifying the <code>target-role</code> and <code>is-managed</code> meta
attributes which effectively enables users in this role to
stop/start and manage/unmanage the resource.  The constraints
write access rule allows moving the resource around.  Finally, the
user is granted read access to the resource definition.</p></div>
<div class="paragraph"><p>The bottom four rules are the absolute minimum read permissions
necessary for proper operation of various Pacemaker tools,
including <code>crm_mon</code> and the shell.  This is fine for viewing
cluster status, but there are some tools for which this will
not be sufficient access (notably <code>crm_simulate</code>), which is why it is
generally recommended that read access be allowed to the entire
CIB.</p></div>
</div>
</div>
</div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Last updated
 2019-06-06 11:06:20 EDT
</div>
</div>
</body>
</html>
